using Scenario_Editor.Addin.Traffic;
using System;
using System.Collections.Generic;
using System.IO;

namespace CustomRoad
{
    public struct RoadProperties
    {
        #region Private Fields

        private const byte VERSION = 0x03;
        private float inclinationStart, inclinationMiddle, inclinationEnd;
        private float maximumMiddleLineSegemet;
        private bool pinToTerrain;
        private List<RoadModifer> properties;
        private CustomRoad.streetTool.RoadType roadType;
        private WR2Traffic wr2Traffic;

        #endregion Private Fields

        #region Public Constructors

        public RoadProperties(List<RoadModifer> properties, bool pinToTerrain)
        {
            this.roadType = streetTool.RoadType.Repeat;
            this.wr2Traffic = new WR2Traffic(false, false, 1, 10.0f, 20.0f, 50.0f, 1, 10.0f, 20.0f, 50.0f, 0);
            this.properties = properties;
            this.pinToTerrain = pinToTerrain;
            this.inclinationStart = 0;
            this.inclinationMiddle = 0;
            this.inclinationEnd = 0;
            this.maximumMiddleLineSegemet = Engine.GeoMath.LENGTH_OF_ROADPIECE;
        }

        #endregion Public Constructors

        #region Internal Constructors

        internal RoadProperties(RoadProperties roadProperties)
        {
            this.inclinationStart = roadProperties.inclinationStart;
            this.inclinationEnd = roadProperties.inclinationEnd;
            this.inclinationMiddle = roadProperties.inclinationMiddle;
            this.maximumMiddleLineSegemet = roadProperties.maximumMiddleLineSegemet;
            this.pinToTerrain = roadProperties.pinToTerrain;
            this.properties = new List<RoadModifer>(roadProperties.properties);
            this.roadType = roadProperties.roadType;
            this.wr2Traffic = roadProperties.wr2Traffic;
        }

        #endregion Internal Constructors

        #region Public Properties

        public float InclinationEnd
        {
            get { return inclinationEnd; }
            set { inclinationEnd = value; }
        }

        public float InclinationMiddle
        {
            get { return inclinationMiddle; }
            set { inclinationMiddle = value; }
        }

        public float InclinationStart
        {
            get { return inclinationStart; }
            set { inclinationStart = value; }
        }

        public float MaximumMiddleLineSegemet
        {
            get { return maximumMiddleLineSegemet; }
            set { maximumMiddleLineSegemet = value; }
        }

        public bool PinToTerrain
        {
            get { return this.pinToTerrain; }
            set { this.pinToTerrain = value; }
        }

        public List<RoadModifer> Properties
        {
            get { return properties; }
            set { properties = value; }
        }

        public CustomRoad.streetTool.RoadType RoadType
        {
            get { return roadType; }
            set { roadType = value; }
        }

        public WR2Traffic Wr2Traffic
        {
            get { return wr2Traffic; }
            set { wr2Traffic = value; }
        }

        #endregion Public Properties

        #region Public Methods

        public static RoadProperties FromStream(BinaryReader br)
        {
            switch (br.ReadByte())
            {
                case 0x01:
                    return LoadV1(br);

                case 0x02:
                    return LoadV2(br);

                case 0x03:
                    return LoadV3(br);
            }
            throw new NotImplementedException();
        }

        public void ToStream(BinaryWriter bw)
        {
            bw.Write(VERSION);
            bw.Write((short)this.roadType);
            bw.Write(this.PinToTerrain);
            bw.Write(this.inclinationStart);
            bw.Write(this.inclinationMiddle);
            bw.Write(this.inclinationEnd);
            bw.Write(this.MaximumMiddleLineSegemet);
            this.wr2Traffic.ToStream(bw);
            bw.Write(this.properties.Count);
            for (int i = 0; i < this.properties.Count; i++)
            {
                this.properties[i].ToStream(bw);
            }
        }

        #endregion Public Methods

        #region Private Methods

        private static RoadProperties LoadV1(BinaryReader br)
        {
            RoadProperties roadProperties = new RoadProperties(new List<RoadModifer>(), false);

            roadProperties.roadType = (streetTool.RoadType)br.ReadInt16();
            roadProperties.wr2Traffic = WR2Traffic.FromStrean(br);
            int numberOfRoadModifers = br.ReadInt32();

            for (int i = 0; i < numberOfRoadModifers; i++)
            {
                roadProperties.properties.Add(RoadModifer.FromStream(br));
            }

            return roadProperties;
        }

        private static RoadProperties LoadV2(BinaryReader br)
        {
            RoadProperties roadProperties = new RoadProperties(new List<RoadModifer>(), false);

            roadProperties.roadType = (streetTool.RoadType)br.ReadInt16();
            roadProperties.PinToTerrain = br.ReadBoolean();
            roadProperties.wr2Traffic = WR2Traffic.FromStrean(br);
            int numberOfRoadModifers = br.ReadInt32();

            for (int i = 0; i < numberOfRoadModifers; i++)
            {
                roadProperties.properties.Add(RoadModifer.FromStream(br));
            }

            return roadProperties;
        }

        private static RoadProperties LoadV3(BinaryReader br)
        {
            RoadProperties roadProperties = new RoadProperties(new List<RoadModifer>(), false);

            roadProperties.roadType = (streetTool.RoadType)br.ReadInt16();
            roadProperties.PinToTerrain = br.ReadBoolean();
            roadProperties.inclinationStart = br.ReadSingle();
            roadProperties.inclinationMiddle = br.ReadSingle();
            roadProperties.inclinationEnd = br.ReadSingle();
            roadProperties.MaximumMiddleLineSegemet = br.ReadSingle();
            roadProperties.wr2Traffic = WR2Traffic.FromStrean(br);
            int numberOfRoadModifers = br.ReadInt32();

            for (int i = 0; i < numberOfRoadModifers; i++)
            {
                roadProperties.properties.Add(RoadModifer.FromStream(br));
            }

            return roadProperties;
        }

        #endregion Private Methods
    }
}